%%%-----------------------------------------------------------------------------
%%% @doc
%%% apn_server app
%%%
%%% @end
%%%-----------------------------------------------------------------------------

-module(apn_server_app).

-behaviour(application).


-define(PRINT_MSG(Msg), io:format(Msg)).

-define(PRINT(Format, Args), io:format(Format, Args)).

%% Application callbacks
-export([start/2, stop/1]).

%% ===================================================================
%% Application callbacks
%% ===================================================================
start(_StartType, _StartArgs) ->
    print_banner(),
    {ok, Sup} =  apn_server_sup:start_link(),
    start_servers(Sup),
    register(apn_server, self()),
    print_vsn(),
    connect_cluster(),
    apn_server_reloader:start(),
    apn_server_recompiler:start(),
    {ok, Sup}.

print_banner() ->
    ?PRINT("starting apn_server on node '~s'~n", [node()]).

print_vsn() ->
    {ok, Vsn} = application:get_key(vsn),
    {ok, Desc} = application:get_key(description),
    ?PRINT("~s ~s is running now~n", [Desc, Vsn]).


start_servers(Sup) ->
    {ok, DevCertFileOpts} = application:get_env(dev_cert_file),
    {ok, ProCertFileOpts} = application:get_env(pro_cert_file),
    lists:foreach(
        fun({Name, F}) when is_function(F) ->
            ?PRINT("~s is starting...", [Name]),
            F(),
            ?PRINT_MSG("[done]~n");
           ({Name, Server}) ->
            ?PRINT("~s is starting...", [Name]),
            start_child(Sup, Server),
            ?PRINT_MSG("[done]~n");
           ({Name, Server, Opts}) ->
            ?PRINT("~s is starting...", [ Name]),
            start_child(Sup, Server, Opts),
            ?PRINT_MSG("[done]~n")
        end,
        [{"apn_server connect pool manager", apn_server_connect_pool_sup},
         {"apn_server connect manager", apn_server_connect_manager_sup, {DevCertFileOpts, ProCertFileOpts}}
        ]).

start_child(Sup, {supervisor, Name}) ->
    supervisor:start_child(Sup, supervisor_spec(Name));
start_child(Sup, Name) when is_atom(Name) ->
    {ok, _ChiId} = supervisor:start_child(Sup, worker_spec(Name)).

start_child(Sup, {supervisor, Name}, Opts) ->
    supervisor:start_child(Sup, supervisor_spec(Name, Opts));
start_child(Sup, Name, Opts) when is_atom(Name) ->
    {ok, _ChiId} = supervisor:start_child(Sup, worker_spec(Name, Opts)).

%%TODO: refactor...
supervisor_spec(Name) ->
    {Name,{Name, start_link, []}, permanent, infinity, supervisor, [Name]}.
supervisor_spec(Name, Opts) ->
    {Name,{Name, start_link, [Opts]}, permanent, infinity, supervisor, [Name]}.
worker_spec(Name) ->
    {Name, {Name, start_link, []}, permanent, 5000, worker, [Name]}.
worker_spec(Name, Opts) -> 
    {Name, {Name, start_link, [Opts]}, permanent, 5000, worker, [Name]}.


connect_cluster() -> 
    {ok, Node} = application:get_env(master),
    case net_adm:ping(Node) of
        pang ->
            io:format("connect master server ~p fail~n", [Node]);
        pong ->
            io:format("connect master server ~p succeed~n", [Node])
    end.


stop(_State) ->
    ok.